/**
 * 文件模型
 * PC微信聊天应用 - 文件上传和管理
 */

const { db } = require('../config/database');
const path = require('path');
const fs = require('fs').promises;
const crypto = require('crypto');

class File {
  /**
   * 保存文件信息到数据库
   * @param {Object} fileData 文件数据
   * @returns {Promise<number>} 文件ID
   */
  static async create(fileData) {
    try {
      const {
        originalName,
        storedName,
        filePath,
        fileSize,
        fileType,
        mimeType,
        uploadedBy
      } = fileData;

      const sql = `
        INSERT INTO files (
          original_name, stored_name, file_path, file_size, 
          file_type, mime_type, uploaded_by
        ) VALUES (?, ?, ?, ?, ?, ?, ?)
      `;

      const result = await db.query(sql, [
        originalName, storedName, filePath, fileSize,
        fileType, mimeType, uploadedBy
      ]);

      return result.insertId;
    } catch (error) {
      console.error('保存文件信息错误:', error);
      throw error;
    }
  }

  /**
   * 根据存储名称查找文件
   * @param {string} storedName 存储文件名
   * @returns {Promise<Object|null>} 文件信息
   */
  static async findByStoredName(storedName) {
    try {
      const sql = `
        SELECT 
          f.id, f.original_name, f.stored_name, f.file_path,
          f.file_size, f.file_type, f.mime_type, f.created_at,
          u.nickname as uploader_name
        FROM files f
        LEFT JOIN users u ON f.uploaded_by = u.id
        WHERE f.stored_name = ?
      `;
      
      const files = await db.query(sql, [storedName]);
      return files.length > 0 ? files[0] : null;
    } catch (error) {
      console.error('查找文件错误:', error);
      throw error;
    }
  }

  /**
   * 根据用户ID获取文件列表
   * @param {number} userId 用户ID
   * @param {string} fileType 文件类型过滤
   * @param {number} limit 限制数量
   * @param {number} offset 偏移量
   * @returns {Promise<Array>} 文件列表
   */
  static async getUserFiles(userId, fileType = null, limit = 20, offset = 0) {
    try {
      let sql = `
        SELECT 
          id, original_name, stored_name, file_size, 
          file_type, mime_type, created_at
        FROM files
        WHERE uploaded_by = ?
      `;
      
      const params = [userId];
      
      if (fileType) {
        sql += ' AND file_type = ?';
        params.push(fileType);
      }
      
      sql += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
      params.push(limit, offset);
      
      return await db.query(sql, params);
    } catch (error) {
      console.error('获取用户文件列表错误:', error);
      throw error;
    }
  }

  /**
   * 生成唯一的文件名
   * @param {string} originalName 原始文件名
   * @returns {string} 唯一文件名
   */
  static generateUniqueFileName(originalName) {
    const ext = path.extname(originalName);
    const timestamp = Date.now();
    const random = crypto.randomBytes(8).toString('hex');
    return `${timestamp}_${random}${ext}`;
  }

  /**
   * 获取文件类型
   * @param {string} mimeType MIME类型
   * @returns {string} 文件类型
   */
  static getFileType(mimeType) {
    if (mimeType.startsWith('image/')) return 'image';
    if (mimeType.startsWith('video/')) return 'video';
    if (mimeType.startsWith('audio/')) return 'audio';
    if (mimeType.includes('pdf')) return 'pdf';
    if (mimeType.includes('word') || mimeType.includes('document')) return 'document';
    if (mimeType.includes('excel') || mimeType.includes('spreadsheet')) return 'spreadsheet';
    if (mimeType.includes('powerpoint') || mimeType.includes('presentation')) return 'presentation';
    if (mimeType.includes('zip') || mimeType.includes('rar') || mimeType.includes('7z')) return 'archive';
    return 'other';
  }

  /**
   * 检查文件是否存在
   * @param {string} filePath 文件路径
   * @returns {Promise<boolean>} 文件是否存在
   */
  static async fileExists(filePath) {
    try {
      await fs.access(filePath);
      return true;
    } catch {
      return false;
    }
  }

  /**
   * 删除文件
   * @param {number} fileId 文件ID
   * @param {number} userId 用户ID
   * @returns {Promise<boolean>} 删除结果
   */
  static async delete(fileId, userId) {
    try {
      // 先获取文件信息
      const sql = 'SELECT file_path, uploaded_by FROM files WHERE id = ?';
      const files = await db.query(sql, [fileId]);
      
      if (files.length === 0) return false;
      
      const file = files[0];
      
      // 检查权限
      if (file.uploaded_by !== userId) return false;
      
      // 删除数据库记录
      const deleteSql = 'DELETE FROM files WHERE id = ? AND uploaded_by = ?';
      const result = await db.query(deleteSql, [fileId, userId]);
      
      if (result.affectedRows > 0) {
        // 删除物理文件
        try {
          if (await this.fileExists(file.file_path)) {
            await fs.unlink(file.file_path);
          }
        } catch (error) {
          console.error('删除物理文件错误:', error);
        }
        return true;
      }
      
      return false;
    } catch (error) {
      console.error('删除文件错误:', error);
      throw error;
    }
  }

  /**
   * 获取文件统计信息
   * @param {number} userId 用户ID
   * @returns {Promise<Object>} 统计信息
   */
  static async getStats(userId) {
    try {
      const sql = `
        SELECT 
          COUNT(*) as total_files,
          SUM(file_size) as total_size,
          file_type,
          COUNT(*) as type_count
        FROM files
        WHERE uploaded_by = ?
        GROUP BY file_type
      `;
      
      const stats = await db.query(sql, [userId]);
      
      // 获取总统计
      const totalSql = `
        SELECT 
          COUNT(*) as total_files,
          COALESCE(SUM(file_size), 0) as total_size
        FROM files
        WHERE uploaded_by = ?
      `;
      
      const totalStats = await db.query(totalSql, [userId]);
      
      return {
        total: totalStats[0],
        byType: stats
      };
    } catch (error) {
      console.error('获取文件统计错误:', error);
      throw error;
    }
  }

  /**
   * 清理过期文件
   * @param {number} days 保留天数
   * @returns {Promise<number>} 清理的文件数量
   */
  static async cleanupExpiredFiles(days = 30) {
    try {
      // 获取过期文件列表
      const sql = `
        SELECT id, file_path
        FROM files
        WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)
      `;
      
      const expiredFiles = await db.query(sql, [days]);
      
      if (expiredFiles.length === 0) return 0;
      
      let cleanedCount = 0;
      
      for (const file of expiredFiles) {
        try {
          // 删除物理文件
          if (await this.fileExists(file.file_path)) {
            await fs.unlink(file.file_path);
          }
          
          // 删除数据库记录
          await db.query('DELETE FROM files WHERE id = ?', [file.id]);
          cleanedCount++;
        } catch (error) {
          console.error(`清理文件 ${file.id} 错误:`, error);
        }
      }
      
      return cleanedCount;
    } catch (error) {
      console.error('清理过期文件错误:', error);
      throw error;
    }
  }

  /**
   * 验证文件类型
   * @param {string} mimeType MIME类型
   * @param {Array} allowedTypes 允许的类型
   * @returns {boolean} 是否允许
   */
  static validateFileType(mimeType, allowedTypes = []) {
    if (allowedTypes.length === 0) {
      // 默认允许的文件类型
      const defaultAllowed = [
        'image/jpeg', 'image/png', 'image/gif', 'image/webp',
        'video/mp4', 'video/avi', 'video/mov',
        'audio/mp3', 'audio/wav', 'audio/ogg',
        'application/pdf',
        'application/msword',
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'application/vnd.ms-excel',
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        'text/plain'
      ];
      return defaultAllowed.includes(mimeType);
    }
    
    return allowedTypes.includes(mimeType);
  }

  /**
   * 验证文件大小
   * @param {number} fileSize 文件大小（字节）
   * @param {number} maxSize 最大大小（字节）
   * @returns {boolean} 是否允许
   */
  static validateFileSize(fileSize, maxSize = 50 * 1024 * 1024) { // 默认50MB
    return fileSize <= maxSize;
  }
}

module.exports = File;
